"use strict";
var util = require('util');
var RpcBase = require('./RpcBase.js');

var __qRequest = 'request_to_{type}';
var __qReply = 'reply_to_{appId}';

function RpcClient(service) {
	var self = this;
	self.init(function() {
		console.log('init done, id=%s', self.__id);
		__prepareChannel(self, service);
	});
}
util.inherits(RpcClient, RpcBase);
module.exports = RpcClient;

function __prepareChannel(obj, service) {
	// console.log('__prepareChannel');
	var conn = obj.__mqconn;
	var ch = null;

	if (obj.__mqch) {
		ch = obj.__mqch;
		prepareMqReplyChannel();
		return;
	}
	conn.createChannel(function(err, channel) {
		if (err) throw err;
		obj.__mqch = channel;
		ch = channel;
		prepareMqReplyChannel();
	});

	function prepareMqReplyChannel() {
		var qReply = __qReply.replace('{appId}', obj.__id);
		ch.assertQueue(qReply, {
			exclusive: true
		}, function(err, q) {
			if (err) throw err;
			// console.log('create queue %s', qReply);
			ch.consume(qReply, function(msg) {
				ch.ack(msg); // ack
				console.log(' [receive-reply] content=%s,msgId=%s', msg.content, msg.properties.correlationId);
				__handleReply(obj, msg);
			});
			__createProxy(obj, service);
		});
	}
}


function __handleReply(obj, msg) {
	var msgId = msg.properties.correlationId;
	// console.log(' [receive-reply] id=' + msgId);
	var cb = obj.rpcCallback[msgId];
	// console.log(typeof cb);
	// console.log(JSON.stringify(cb));
	if (!cb) {
		console.error('no callback with msgId = %s', msgId);
	} else {
		var cnt = msg.content;
		var args = JSON.parse(cnt);
		cb.apply(null, args);
	}
}

function __createProxy(obj, service) {
	// console.log('__createProxy');
	var keys = [];
	if (typeof service === 'function') {
		obj.__server = new service();
		keys = Object.keys(service.prototype);
	} else {
		obj.__server = service;
	}
	keys = keys.concat(Object.keys(service));

	obj.rpcCallback = {};
	obj.msgId = 1;

	var items = [];
	for (var key of keys) {
		if (typeof obj.__server[key] === 'function') {
			// console.log('key=%s', key);
			items.push({
				key: key,
				fun: obj.__server[key]
			});
		}
	}

	__setupProxy(obj, items);
}

function __setupProxy(obj, keyFuns) {
	var ch = obj.__mqch;
	var qSend = __qRequest.replace('{type}', obj.__server.type);
	ch.assertQueue(qSend, {
		durable: true
	}, function(err, q) {
		setProxy(q, keyFuns);
	});

	function setProxy(q, keyFuns) {
		keyFuns.forEach(function(item) {
			var key = item.key;
			var fun = item.fun;
			if (obj[key] !== undefined) {
				throw new Error("don't use the method name:%s", key);
			}
			console.log(' has method %s', key);
			obj[key] = function() {
				var msgId = (obj.msgId++) + '';
				var args = Array.prototype.slice.call(arguments);
				if (typeof args[args.length - 1] === 'function') {
					var requestCb = args.splice(-1, 1)[0];
					// console.log('save cb, id=%s',msgId);
					obj.rpcCallback[msgId] = requestCb; // put callback to list
				}
				var sendArgs = {
					method: key,
					args: args
				};
				console.log(' [send-request], args=%s, id=%s, replyTo=%s', JSON.stringify(sendArgs), msgId, obj.__id);

				ch.sendToQueue(qSend, new Buffer(JSON.stringify(sendArgs)), {
					correlationId: msgId,
					replyTo: obj.__id + '',
					persisitent: true,
				});
			}
		});
	}
}